package com.zodiac.app.datathinking.szse.b0602;

import lombok.Builder;
import lombok.Data;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

@Component
public class B0602Downloader {
    private final RestTemplate restTemplate = new RestTemplate();

    private static final String DOWNLOAD_URL_PREFIX = "http://disc.static.szse.cn/download";

    @Retryable(value = RetryException.class, maxAttempts = 5, backoff = @Backoff(delay = 1000, multiplier = 2))
    public Response download(Request request) {
        final B0602Model model = request.getModel();
        final File storePath = request.getStorePath();
        final String downloadUrl = DOWNLOAD_URL_PREFIX + model.getReportPath();

        final String year = model.getReportYear();
        final String month = B0602Extractor.ReportType.valueOf(model.getReportType()).getMonth();
        final String stockCode = model.getStockCode();
        final Path target = Paths.get(storePath.getAbsolutePath(), year, month, stockCode, stockCode + ".pdf");

        try {
            HttpEntity<Object> entity = new HttpEntity<>(new HttpHeaders());
            byte[] body = restTemplate.exchange(downloadUrl, HttpMethod.GET, entity, byte[].class).getBody();
            if (!target.toFile().getParentFile().exists()) {
                target.toFile().getParentFile().mkdirs();
            }
            if (!target.toFile().exists()) {
                target.toFile().createNewFile();
            }
            Files.write(target, body);
            return Response.success(request);
        } catch (Exception e) {
            throw new RetryException(request);
        }
    }

    @Recover
    protected Response recover(RetryException e) {
        return Response.failure(e.getRequest());
    }

    @Builder
    @Data
    public static class Request {
        private File storePath;
        private B0602Model model;
    }

    @Data
    public static class Response {
        private Request request;
        private boolean success;

        public Response(Request request, boolean success) {
            this.request = request;
            this.success = success;
        }

        public static Response success(Request request) {
            return new Response(request, true);
        }

        public static Response failure(Request request) {
            return new Response(request, false);
        }
    }

    @Data
    public static class RetryException extends RuntimeException {
        private Request request;

        public RetryException(Request request) {
            this.request = request;
        }

        public RetryException(Throwable cause, Request request) {
            super(cause);
            this.request = request;
        }
    }

}
